#include "glwidget.h"

GLWidget::GLWidget(QWidget *parent)
    : QGLWidget(parent)
{
    Theta = pi/6;
    Phi = pi/6;
    R = topR = frontR = rightR = planeR = 100;
    //COMBINE
    mode = CELL_TRANSLATE;
    tmpMode = CELL_TRANSLATE;
    //mode = CELL_SELECT;
    //tmpMode = CELL_SELECT;
    viewMode =  CELL_PERSPECTIVE;
    offsetX = topOffsetX = frontOffsetX = rightOffsetX = planeOffsetX = 0.0;
    offsetY = topOffsetY = frontOffsetY = rightOffsetY = planeOffsetY = 0.0;
    keyValue = -1;
    selectObject = -1;
    secondSelectObject = -1;
    selectTranslateAxis = selectRotateAxis = selectScaleAxis = -1;
    displayMode = CELL_TRIANGLE;
    glandular = new CellObject();
    plane = new IntersectionPlane();
    paintMode = CELL_NOPAINT;
    isAreaSelected = false;
    selectMode = CELL_SELECT;
    editFeather = 0.0;
    copyObject = -1;
    sphereNum = cylinderNum = cubeNum = meshNum = 0;
}

GLWidget::~GLWidget()
{
    //cout << "GLWidget::~GLWidget()" << endl;
}

void GLWidget::newScene()
{
    Theta = pi/6;
    Phi = pi/6;
    R = topR = frontR = rightR = planeR = 100;
    //COMBINE
    mode = CELL_TRANSLATE;
    tmpMode = CELL_TRANSLATE;
    //mode = CELL_SELECT;
    //tmpMode = CELL_SELECT;
    viewMode =  CELL_PERSPECTIVE;
    offsetX = topOffsetX = frontOffsetX = rightOffsetX = planeOffsetX = 0.0;
    offsetY = topOffsetY = frontOffsetY = rightOffsetY = planeOffsetY = 0.0;
    keyValue = -1;
    selectObject = -1;
    secondSelectObject = -1;
    selectTranslateAxis = selectRotateAxis = selectScaleAxis = -1;
    displayMode = CELL_TRIANGLE;
    glandular = new CellObject();
    plane = new IntersectionPlane();
    paintMode = CELL_NOPAINT;
    isAreaSelected = false;
    selectMode = CELL_SELECT;
    editFeather = 0.0;
    copyObject = -1;
    sphereNum = cylinderNum = cubeNum = meshNum = 0;
    objects.clear();
}

void GLWidget::SaveScene(char *filename)
{
    objects[selectObject-2]->SaveCellObject(filename);
}

void GLWidget::setTheta(double angle)
{
    Theta=angle;
}

void GLWidget::setPhi(double angle)
{
    Phi=angle;
}

void GLWidget::setR(double angle)
{
    R=angle;
}

void GLWidget::setTranslateX(double length)
{
    if (selectObject == 0)
        glandular->setTranslateX(length);
    else if (selectObject>1)
        (objects[selectObject-2])->setTranslateX(length);
    QString t = QString::number(length);
    emit xTranslationChanged(t);
}

void GLWidget::setTranslateY(double length)
{
    if (selectObject == 0)
        glandular->setTranslateY(length);
    else if (selectObject>1)
        (objects[selectObject-2])->setTranslateY(length);
    QString t = QString::number(length);
    emit yTranslationChanged(t);
}

void GLWidget::setTranslateZ(double length)
{
    if (selectObject == 0)
        glandular->setTranslateZ(length);
    else if (selectObject>1)
        (objects[selectObject-2])->setTranslateZ(length);
    QString t = QString::number(length);
    emit zTranslationChanged(t);
}

void GLWidget::addTranslateCtrlPt1X(double length)
{
    (objects[selectObject-2])->addTranslateCtrlPt1X(length);

    length = ((objects[selectObject-2])->getCtrlPt1X() + (objects[selectObject-2])->getCtrlPt2X())/2;

    QString t = QString::number(length);
    emit xTranslationChanged(t);
}

void GLWidget::addTranslateCtrlPt1Y(double length)
{
    (objects[selectObject-2])->addTranslateCtrlPt1Y(length);

    length = ((objects[selectObject-2])->getCtrlPt1Y() + (objects[selectObject-2])->getCtrlPt2Y())/2;

    QString t = QString::number(length);
    emit yTranslationChanged(t);
}

void GLWidget::addTranslateCtrlPt1Z(double length)
{
    (objects[selectObject-2])->addTranslateCtrlPt1Z(length);

    length = ((objects[selectObject-2])->getCtrlPt1Z() + (objects[selectObject-2])->getCtrlPt2Z())/2;

    QString t = QString::number(length);
    emit zTranslationChanged(t);
}

void GLWidget::addTranslateCtrlPt2X(double length)
{
    (objects[selectObject-2])->addTranslateCtrlPt2X(length);

    length = ((objects[selectObject-2])->getCtrlPt1X() + (objects[selectObject-2])->getCtrlPt2X())/2;

    QString t = QString::number(length);
    emit xTranslationChanged(t);
}

void GLWidget::addTranslateCtrlPt2Y(double length)
{
    (objects[selectObject-2])->addTranslateCtrlPt2Y(length);

    length = ((objects[selectObject-2])->getCtrlPt1Y() + (objects[selectObject-2])->getCtrlPt2Y())/2;

    QString t = QString::number(length);
    emit yTranslationChanged(t);
}

void GLWidget::addTranslateCtrlPt2Z(double length)
{
    (objects[selectObject-2])->addTranslateCtrlPt2Z(length);

    length = ((objects[selectObject-2])->getCtrlPt1Z() + (objects[selectObject-2])->getCtrlPt2Z())/2;

    QString t = QString::number(length);
    emit zTranslationChanged(t);
}

void GLWidget::addTranslateX(double length)
{
    if (selectObject == 0) {
        glandular->addTranslateX(length);
        length += glandular->getTranslateX();
    }
    else if (selectObject>1) {
        (objects[selectObject-2])->addTranslateX(length);
        length += (objects[selectObject-2])->getTranslateX();
    }
    QString t = QString::number(length);
    emit xTranslationChanged(t);
}

void GLWidget::addTranslateY(double length)
{
    if (selectObject == 0) {
        glandular->addTranslateY(length);
        length += glandular->getTranslateY();
    }
    else if (selectObject>1) {
        (objects[selectObject-2])->addTranslateY(length);
        length += (objects[selectObject-2])->getTranslateY();
    }
    QString t = QString::number(length);
    emit yTranslationChanged(t);
}

void GLWidget::addTranslateZ(double length)
{
    if (selectObject == 0)
    {
        glandular->addTranslateZ(length);
        length += glandular->getTranslateZ();
    }
    else if (selectObject>1)
    {
        (objects[selectObject-2])->addTranslateZ(length);
        length += (objects[selectObject-2])->getTranslateZ();
    }
    QString t = QString::number(length);
    emit zTranslationChanged(t);
}

void GLWidget::setRotateX(double angle)
{
    if (angle >= 360.0)
        angle -= 360;
    else if(angle < 0.0)
        angle += 360;
    if (selectObject == 0)
        glandular->setRotateX(angle);
    else if (selectObject>1)
        (objects[selectObject-2])->setRotateX(angle);
    QString t = QString::number(angle);
    emit xRotationChanged(t);
}

void GLWidget::setRotateY(double angle)
{
    if(angle >= 360.0)
        angle -= 360;
    else if(angle < 0.0)
        angle += 360;
    if (selectObject == 0)
        glandular->setRotateY(angle);
    else if (selectObject>1)
        (objects[selectObject-2])->setRotateY(angle);
    QString t = QString::number(angle);
    emit yRotationChanged(t);
}

void GLWidget::setRotateZ(double angle)
{
    if (selectObject == 0)
        glandular->setRotateZ(angle);
    else if (selectObject>1)
        (objects[selectObject-2])->setRotateZ(angle);
    QString t = QString::number(angle);
    emit zRotationChanged(t);
}

void GLWidget::addRotateX(double angle)
{
    if (selectObject == 0) {
        glandular->addRotateX(angle);
        angle = glandular->getRotateX();
    }
    else if (selectObject > 1) {
        (objects[selectObject-2])->addRotateX(angle);
        angle = (objects[selectObject-2])->getRotateX();
    }
    QString t = QString::number(angle);
    emit xRotationChanged(t);
}

void GLWidget::addRotateY(double angle)
{
    if (selectObject == 0) {
        glandular->addRotateY(angle);
        angle = glandular->getRotateY();
    }
    else if (selectObject > 1) {
        (objects[selectObject-2])->addRotateY(angle);
        angle = (objects[selectObject-2])->getRotateY();
    }
    QString t = QString::number(angle);
    emit yRotationChanged(t);
}

void GLWidget::addRotateZ(double angle)
{
    if (selectObject == 0) {
        glandular->addRotateZ(angle);
        angle = glandular->getRotateZ();
    }
    else if (selectObject > 1) {
        (objects[selectObject-2])->addRotateZ(angle);
        angle = (objects[selectObject-2])->getRotateZ();
    }
    QString t = QString::number(angle);
    emit zRotationChanged(t);
}

void GLWidget::setScaleX(double s)
{
    if (selectObject == 0)
        glandular->setScaleX(s);
    else if (selectObject>1)
        (objects[selectObject-2])->setScaleX(s);
    QString t = QString::number(s);
    emit xScalationChanged(t);
}

void GLWidget::setScaleY(double s)
{
    if (selectObject == 0)
        glandular->setScaleY(s);
    else if (selectObject>1)
        (objects[selectObject-2])->setScaleY(s);
    QString t = QString::number(s);
    emit yScalationChanged(t);
}

void GLWidget::setScaleZ(double s)
{
    if (selectObject == 0)
        glandular->setScaleZ(s);
    else if (selectObject>1)
        (objects[selectObject-2])->setScaleZ(s);
    QString t = QString::number(s);
    emit zScalationChanged(t);
}

void GLWidget::setInputType()
{
    int t=-1;
    if (selectObject == -1)
        t = CELL_NONE;
    else if (selectObject == 0)
        t = CELL_MESH;
    else if (selectObject > 1)
        t = (objects[selectObject-2])->getType();
    emit inputTypeChanged(t);
}

void GLWidget::setTranslateX(QString l)
{
    double t = l.toDouble();
    if (selectObject == 0)
        glandular->setTranslateX(t);
    else if (selectObject>1)
        (objects[selectObject-2])->setTranslateX(t);
    updateGL();
}

void GLWidget::setTranslateY(QString l)
{
    double t = l.toDouble();
    if (selectObject == 0)
        glandular->setTranslateY(t);
    else if (selectObject>1)
        (objects[selectObject-2])->setTranslateY(t);
    updateGL();
}

void GLWidget::setTranslateZ(QString l)
{
    double t = l.toDouble();
    if (selectObject == 0)
        glandular->setTranslateZ(t);
    else if (selectObject>1)
        (objects[selectObject-2])->setTranslateZ(t);
    updateGL();
}

void GLWidget::setRotateX(QString l)
{
    double t = l.toDouble();
    if (selectObject == 0)
        glandular->setRotateX(t);
    else if (selectObject>1)
        (objects[selectObject-2])->setRotateX(t);
    updateGL();
}

void GLWidget::setRotateY(QString l)
{
    double t = l.toDouble();
    if (selectObject == 0)
        glandular->setRotateY(t);
    else if (selectObject>1)
        (objects[selectObject-2])->setRotateY(t);
    updateGL();
}

void GLWidget::setRotateZ(QString l)
{
    double t = l.toDouble();
    if (selectObject == 0)
        glandular->setRotateZ(t);
    else if (selectObject>1)
        (objects[selectObject-2])->setRotateZ(t);
    updateGL();
}

void GLWidget::setScaleX(QString l)
{
    double t = l.toDouble();
    if (selectObject == 0)
        glandular->setScaleX(t);
    else if (selectObject>1)
        (objects[selectObject-2])->setScaleX(t);
    updateGL();
}

void GLWidget::setScaleY(QString l)
{
    double t = l.toDouble();
    if (selectObject == 0)
        glandular->setScaleY(t);
    else if (selectObject>1)
        (objects[selectObject-2])->setScaleY(t);
    updateGL();
}

void GLWidget::setScaleZ(QString l)
{
    double t = l.toDouble();
    if (selectObject == 0)
        glandular->setScaleZ(t);
    else if (selectObject>1)
        (objects[selectObject-2])->setScaleZ(t);
    updateGL();
}

void GLWidget::setEditFeather(QString l)
{
    double t = l.toDouble();
    editFeather = t/100.0;
    updateGL();
}

void GLWidget::setSphereRadius(QString l)
{
    double t = l.toDouble();
    if (t>0.0)
        (objects[selectObject-2])->buildSphere(t, (objects[selectObject-2])->getSphereHeightSeg(), (objects[selectObject-2])->getSphereAxisSeg());
    updateGL();
}

void GLWidget::setSphereHeightSeg(QString l)
{
    int t = l.toInt();
    if (t>=2)
        (objects[selectObject-2])->buildSphere((objects[selectObject-2])->getSphereRadius(), t, (objects[selectObject-2])->getSphereAxisSeg());
    updateGL();
}

void GLWidget::setSphereAxisSeg(QString l)
{
    int t = l.toInt();
    if (t>=3)
        (objects[selectObject-2])->buildSphere((objects[selectObject-2])->getSphereRadius(), (objects[selectObject-2])->getSphereHeightSeg(), t);
    updateGL();
}

void GLWidget::setCylinderRadius(QString l)
{
    double t = l.toDouble();
    if (t>0.0)
        (objects[selectObject-2])->buildCylinder(t, (objects[selectObject-2])->getCylinderHeight(),
            (objects[selectObject-2])->getCylinderAxisSeg(), (objects[selectObject-2])->getCylinderHeightSeg());
    updateGL();
}

void GLWidget::setCylinderHeight(QString l)
{
    double t = l.toDouble();
    if (t>0.0)
        (objects[selectObject-2])->buildCylinder((objects[selectObject-2])->getCylinderRadius(), t,
            (objects[selectObject-2])->getCylinderAxisSeg(), (objects[selectObject-2])->getCylinderHeightSeg());
    updateGL();
}

void GLWidget::setCylinderAxisSeg(QString l)
{
    int t = l.toInt();
    if (t>=3)
        (objects[selectObject-2])->buildCylinder((objects[selectObject-2])->getCylinderRadius(),
            (objects[selectObject-2])->getCylinderHeight(), t, (objects[selectObject-2])->getCylinderHeightSeg());
    updateGL();
}

void GLWidget::setCylinderHeightSeg(QString l)
{
    int t = l.toInt();
    if (t>=1)
        (objects[selectObject-2])->buildCylinder((objects[selectObject-2])->getCylinderRadius(),
            (objects[selectObject-2])->getCylinderHeight(), (objects[selectObject-2])->getCylinderAxisSeg(), t);
    updateGL();
}

void GLWidget::setPlaneWidth(QString l)
{
    double t = l.toDouble();
    if (t>0.0)
        (objects[selectObject-2])->buildPlane(t, (objects[selectObject-2])->getPlaneLength(),
            (objects[selectObject-2])->getPlaneWidthSeg(), (objects[selectObject-2])->getPlaneLengthSeg());
    updateGL();
}

void GLWidget::setPlaneLength(QString l)
{
    double t = l.toDouble();
    if (t>0.0)
        (objects[selectObject-2])->buildPlane((objects[selectObject-2])->getPlaneWidth(), t,
            (objects[selectObject-2])->getPlaneWidthSeg(), (objects[selectObject-2])->getPlaneLengthSeg());
    updateGL();
}

void GLWidget::setPlaneSeg(QString l)
{
    int t = l.toInt();
    if(t>=1) {
        (objects[selectObject-2])->buildPlane((objects[selectObject-2])->getPlaneWidth(),
            (objects[selectObject-2])->getPlaneLength(), t, (objects[selectObject-2])->getPlaneLengthSeg());
        (objects[selectObject-2])->buildPlane((objects[selectObject-2])->getPlaneWidth(),
            (objects[selectObject-2])->getPlaneLength(), (objects[selectObject-2])->getPlaneWidthSeg(), t);
    }
    updateGL();
}

void GLWidget::setCubeWidth(QString l)
{
    double t = l.toDouble();
    if (t>0.0)
        (objects[selectObject-2])->buildCube(t, (objects[selectObject-2])->getCubeHeight(),
            (objects[selectObject-2])->getCubeDepth(), (objects[selectObject-2])->getCubeWidthSeg(),
            (objects[selectObject-2])->getCubeHeightSeg(), (objects[selectObject-2])->getCubeDepthSeg());
    updateGL();
}

void GLWidget::setCubeHeight(QString l)
{
    double t = l.toDouble();
    if (t>0.0)
        (objects[selectObject-2])->buildCube((objects[selectObject-2])->getCubeWidth(), t,
            (objects[selectObject-2])->getCubeDepth(), (objects[selectObject-2])->getCubeWidthSeg(),
            (objects[selectObject-2])->getCubeHeightSeg(), (objects[selectObject-2])->getCubeDepthSeg());
    updateGL();
}

void GLWidget::setCubeDepth(QString l)
{
    double t = l.toDouble();
    if (t>0.0)
        (objects[selectObject-2])->buildCube((objects[selectObject-2])->getCubeWidth(),
            (objects[selectObject-2])->getCubeHeight(), t, (objects[selectObject-2])->getCubeWidthSeg(),
            (objects[selectObject-2])->getCubeHeightSeg(), (objects[selectObject-2])->getCubeDepthSeg());
    updateGL();
}

void GLWidget::setCubeWidthSeg(QString l)
{
    int t = l.toInt();
    if (t>=1)
        (objects[selectObject-2])->buildCube((objects[selectObject-2])->getCubeWidth(),
            (objects[selectObject-2])->getCubeHeight(), (objects[selectObject-2])->getCubeDepth(), t,
            (objects[selectObject-2])->getCubeHeightSeg(), (objects[selectObject-2])->getCubeDepthSeg());
    updateGL();
}

void GLWidget::setCubeHeightSeg(QString l)
{
    int t = l.toInt();
    if (t>=1)
        (objects[selectObject-2])->buildCube((objects[selectObject-2])->getCubeWidth(),
            (objects[selectObject-2])->getCubeHeight(), (objects[selectObject-2])->getCubeDepth(),
            (objects[selectObject-2])->getCubeWidthSeg(), t, (objects[selectObject-2])->getCubeDepthSeg());
    updateGL();
}

void GLWidget::setCubeDepthSeg(QString l)
{
    int t = l.toInt();
    if (t>=1)
        (objects[selectObject-2])->buildCube((objects[selectObject-2])->getCubeWidth(),
            (objects[selectObject-2])->getCubeHeight(), (objects[selectObject-2])->getCubeDepth(),
            (objects[selectObject-2])->getCubeWidthSeg(), (objects[selectObject-2])->getCubeHeightSeg(), t);
    updateGL();
}

void GLWidget::initializeGL()
{
    GLfloat white[] = { 1.0, 1.0, 1.0, 1.0 };		 /* Add one light */
    GLfloat light_pos[] = {100,100,100,1};
    GLfloat light_pos1[] = {-100,-100,-100,1};
    GLfloat light_diffuse[]= { 1.0, 1.0, 1.0, 1.0};
    GLfloat light_specular[]= { 1.0, 1.0, 1.0, 1.0};

    glLightfv(GL_LIGHT0, GL_POSITION, light_pos);
    glLightfv(GL_LIGHT0, GL_AMBIENT, white);
    glLightfv(GL_LIGHT0, GL_DIFFUSE,light_diffuse);
    glLightfv(GL_LIGHT0, GL_SPECULAR,light_specular);
    glLightfv(GL_LIGHT1, GL_POSITION, light_pos1);
    glLightfv(GL_LIGHT1, GL_AMBIENT, white);
    glLightfv(GL_LIGHT1, GL_DIFFUSE,light_diffuse);
    glLightfv(GL_LIGHT0, GL_SPECULAR,light_specular);
    glEnable(GL_LIGHTING);
    glEnable(GL_LIGHT0);
    glEnable(GL_LIGHT1);
    glEnable(GL_DEPTH_TEST);

    glEnable(GL_NORMALIZE);
    glClearColor(68.0/255.0, 68.0/255.0, 68.0/255.0, 1.0f);
}

void GLWidget::paintGL()
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    if (viewMode == CELL_PERSPECTIVE) {
        glMatrixMode(GL_MODELVIEW);
        glLoadIdentity();

        glViewport(0, 0, windowWidth, windowHeight);
        drawBackground();
        //camera movement, rotation, and zooming
        glTranslatef(offsetX,-offsetY,0);
        gluLookAt(R*cos(Phi)*cos(Theta), R*sin(Theta), R*sin(Phi)*cos(Theta),
                  0.0,0.0,0.0, 0.0,1.0,0.0);
        glEnable(GL_DEPTH_TEST);
        glDisable(GL_LIGHTING);
        drawGlandular();
        //plane->DrawPlane(1, selectObject);
        drawWire();

        if (((mode==CELL_SELECT)||(mode==CELL_EDITMESHPOINT)||(mode==CELL_EDITMESHFACE))&&isAreaSelected)
        {
            drawSelectArea(lastPos.x(),lastPos.y(),thisPos.x(),thisPos.y());
        }
        if (selectMode==CELL_EDITMESHPOINT&&mode==CELL_TRANSLATE) {
            Vector3 center;
            if (selectObject==0) {
                if (glandular->selectPointsCenter(center)>0) {
                    drawEditMeshTranslateAxis(center.x, center.y, center.z, glandular->getRotateX(),
                                              glandular->getRotateY(), glandular->getRotateZ());
                }
            } else if (selectObject>1) {
                if (objects[selectObject-2]->selectPointsCenter(center)>0) {
                    drawEditMeshTranslateAxis(center.x, center.y, center.z, objects[selectObject-2]->getRotateX(),
                            objects[selectObject-2]->getRotateY(), objects[selectObject-2]->getRotateZ());
                }
            }
        }
        if (selectMode==CELL_EDITMESHFACE&&mode==CELL_TRANSLATE) {
            Vector3 center;
            if (selectObject==0 && glandular->isSurfaceConstructed()) {
                if (glandular->selectFacesCenter(center)>0) {
                    drawEditMeshTranslateAxis(center.x, center.y, center.z, glandular->getRotateX(),
                                              glandular->getRotateY(), glandular->getRotateZ());
                }
            } else if (selectObject>1) {
                if (objects[selectObject-2]->selectFacesCenter(center)>0) {
                    drawEditMeshTranslateAxis(center.x, center.y, center.z, objects[selectObject-2]->getRotateX(),
                            objects[selectObject-2]->getRotateY(), objects[selectObject-2]->getRotateZ());
                }
            }
        }
        if (selectMode==CELL_SELECT&&mode==CELL_TRANSLATE&&selectObject>=0) {
            drawTranslateAxis(0.0, 0.0, 0.0, selectObject);
            //drawTranslatePoint(selectObject);
        }
        if (selectMode==CELL_SELECT&&mode==CELL_ROTATE&&selectObject>=0) {
            drawRotateAxis(0.0, 0.0, 0.0, selectObject);
        }
        if (selectMode==CELL_SELECT&&mode==CELL_SCALE&&selectObject>=0) {
            drawScaleAxis(0.0, 0.0, 0.0, selectObject);
        }

        glViewport(0, 0, 100, 100);
        drawAxis();
        glViewport(0, 0, windowWidth, windowHeight);
    } else if (viewMode == CELL_FOURVIEW) {
        glMatrixMode(GL_MODELVIEW);
        glLoadIdentity();

        int halfWidth = windowWidth/2;
        int halfHeight = windowHeight/2;
        //left-down, front
        glViewport(0, 0, halfWidth-CELL_FOURVIEWMARGIN, halfHeight-CELL_FOURVIEWMARGIN);
        drawBackground();
        glEnable(GL_DEPTH_TEST);
        glDisable(GL_LIGHTING);
        glMatrixMode(GL_PROJECTION);
        glPushMatrix();
        glLoadIdentity();
        glOrtho(-frontR*sin(pi/8), frontR*sin(pi/8),
                -frontR*sin(pi/8)*(double)windowHeight/(double)windowWidth,
                frontR*sin(pi/8)*(double)windowHeight/(double)windowWidth,-INT_MAX,INT_MAX);
        glMatrixMode(GL_MODELVIEW);
        glLoadIdentity();
        glTranslatef(frontOffsetX,-frontOffsetY,0);
        gluLookAt(frontR*cos(0.0)*cos(0.0), frontR*sin(0.0), frontR*sin(0.0)*cos(0.0),
                  0.0,0.0,0.0, 0.0,1.0,0.0);
        drawGlandular();
        drawWire();
        glMatrixMode(GL_PROJECTION);
        glPopMatrix();

        //right-down, right
        glViewport(halfWidth+CELL_FOURVIEWMARGIN, 0,
                   halfWidth-CELL_FOURVIEWMARGIN, halfHeight-CELL_FOURVIEWMARGIN);
        drawBackground();
        glEnable(GL_DEPTH_TEST);
        glDisable(GL_LIGHTING);
        glMatrixMode(GL_PROJECTION);
        glPushMatrix();
        glLoadIdentity();
        glOrtho(-rightR*sin(pi/8), rightR*sin(pi/8),
                -rightR*sin(pi/8)*(double)windowHeight/(double)windowWidth,
                rightR*sin(pi/8)*(double)windowHeight/(double)windowWidth,-INT_MAX,INT_MAX);
        glMatrixMode(GL_MODELVIEW);
        glLoadIdentity();
        glTranslatef(rightOffsetX,-rightOffsetY,0);
        gluLookAt(rightR*cos(pi/2)*cos(0.0), rightR*sin(0.0), rightR*sin(pi/2)*cos(0.0),
                  0.0,0.0,0.0, 0.0,1.0,0.0);
        drawGlandular();
        drawWire();
        glMatrixMode(GL_PROJECTION);
        glPopMatrix();

        //left-up, top
        glViewport(0, halfHeight+CELL_FOURVIEWMARGIN,
                   halfWidth-CELL_FOURVIEWMARGIN, halfHeight-CELL_FOURVIEWMARGIN);
        drawBackground();
        glEnable(GL_DEPTH_TEST);
        glDisable(GL_LIGHTING);
        glMatrixMode(GL_PROJECTION);
        glPushMatrix();
        glLoadIdentity();
        glOrtho(-topR*sin(pi/8), topR*sin(pi/8),
                -topR*sin(pi/8)*(double)windowHeight/(double)windowWidth,
                topR*sin(pi/8)*(double)windowHeight/(double)windowWidth,-INT_MAX,INT_MAX);
        glMatrixMode(GL_MODELVIEW);
        glLoadIdentity();
        glTranslatef(topOffsetX,-topOffsetY,0);
        gluLookAt(topR*cos(0.0)*cos(pi/2), topR*sin(pi/2), topR*sin(0.0)*cos(pi/2),
                  0.0,0.0,0.0, 0.0,1.0,0.0);
        drawGlandular();
        drawWire();
        glMatrixMode(GL_PROJECTION);
        glPopMatrix();

        //right-up, perspective
        glViewport(halfWidth+CELL_FOURVIEWMARGIN, halfHeight+CELL_FOURVIEWMARGIN,
                   halfWidth-CELL_FOURVIEWMARGIN, halfHeight-CELL_FOURVIEWMARGIN);
        drawBackground();
        glEnable(GL_DEPTH_TEST);
        glDisable(GL_LIGHTING);
        glMatrixMode(GL_MODELVIEW);
        glLoadIdentity();
        glTranslatef(offsetX,-offsetY,0);
        gluLookAt(R*cos(Phi)*cos(Theta), R*sin(Theta), R*sin(Phi)*cos(Theta),
                  0.0,0.0,0.0, 0.0,1.0,0.0);
        drawGlandular();
        drawWire();
    } else if (viewMode == CELL_TOP) {
        glViewport(0, 0, windowWidth, windowHeight);
        drawBackground();
        glEnable(GL_DEPTH_TEST);
        glDisable(GL_LIGHTING);
        glMatrixMode(GL_PROJECTION);
        glPushMatrix();
        glLoadIdentity();
        glOrtho(-topR*sin(pi/8), topR*sin(pi/8),
                -topR*sin(pi/8)*(double)windowHeight/(double)windowWidth,
                topR*sin(pi/8)*(double)windowHeight/(double)windowWidth,-INT_MAX,INT_MAX);
        glMatrixMode(GL_MODELVIEW);
        glLoadIdentity();
        glTranslatef(topOffsetX,-topOffsetY,0);
        gluLookAt(topR*cos(0.0)*cos(pi/2), topR*sin(pi/2), topR*sin(0.0)*cos(pi/2),
                  0.0,0.0,0.0, 0.0,1.0,0.0);
        drawGlandular();
        drawWire();

        glMatrixMode(GL_PROJECTION);
        glPopMatrix();
        glViewport(0, 0, 100, 100);
        drawAxis();
        glViewport(0, 0, windowWidth, windowHeight);
    } else if (viewMode == CELL_FRONT) {
        glViewport(0, 0, windowWidth, windowHeight);
        drawBackground();
        glEnable(GL_DEPTH_TEST);
        glDisable(GL_LIGHTING);
        glMatrixMode(GL_PROJECTION);
        glPushMatrix();
        glLoadIdentity();
        glOrtho(-frontR*sin(pi/8), frontR*sin(pi/8),
                -frontR*sin(pi/8)*(double)windowHeight/(double)windowWidth,
                frontR*sin(pi/8)*(double)windowHeight/(double)windowWidth,-INT_MAX,INT_MAX);
        glMatrixMode(GL_MODELVIEW);
        glLoadIdentity();
        glTranslatef(frontOffsetX,-frontOffsetY,0);
        gluLookAt(frontR*cos(0.0)*cos(0.0), frontR*sin(0.0), frontR*sin(0.0)*cos(0.0),
                  0.0,0.0,0.0, 0.0,1.0,0.0);
        drawGlandular();
        drawWire();

        glMatrixMode(GL_PROJECTION);
        glPopMatrix();
        glViewport(0, 0, 100, 100);
        drawAxis();
        glViewport(0, 0, windowWidth, windowHeight);
    } else if (viewMode == CELL_RIGHT) {
        glViewport(0, 0, windowWidth, windowHeight);
        drawBackground();
        glEnable(GL_DEPTH_TEST);
        glDisable(GL_LIGHTING);
        glMatrixMode(GL_PROJECTION);
        glPushMatrix();
        glLoadIdentity();
        glOrtho(-rightR*sin(pi/8), rightR*sin(pi/8),
                -rightR*sin(pi/8)*(double)windowHeight/(double)windowWidth,
                rightR*sin(pi/8)*(double)windowHeight/(double)windowWidth,-INT_MAX,INT_MAX);
        glMatrixMode(GL_MODELVIEW);
        glLoadIdentity();
        glTranslatef(rightOffsetX,-rightOffsetY,0);
        gluLookAt(rightR*cos(pi/2)*cos(0.0), rightR*sin(0.0), rightR*sin(pi/2)*cos(0.0),
                  0.0,0.0,0.0, 0.0,1.0,0.0);
        drawGlandular();
        drawWire();

        glMatrixMode(GL_PROJECTION);
        glPopMatrix();
        glViewport(0, 0, 100, 100);
        drawAxis();
        glViewport(0, 0, windowWidth, windowHeight);
    } else if (viewMode == CELL_PALNEBACED) {
        glViewport(0, 0, windowWidth, windowHeight);
        drawBackground();
        glEnable(GL_DEPTH_TEST);
        glDisable(GL_LIGHTING);
        glMatrixMode(GL_PROJECTION);
        glPushMatrix();
        glLoadIdentity();
        glOrtho(-planeR*sin(pi/8), planeR*sin(pi/8),
                -planeR*sin(pi/8)*(double)windowHeight/(double)windowWidth,
                planeR*sin(pi/8)*(double)windowHeight/(double)windowWidth,-INT_MAX,INT_MAX);
        glMatrixMode(GL_MODELVIEW);
        glLoadIdentity();
        glTranslatef(planeOffsetX,-planeOffsetY,0);
        gluLookAt(planeR*cos(0.0)*cos(pi/2), planeR*sin(pi/2), planeR*sin(0.0)*cos(pi/2),
                  0.0,0.0,0.0, 0.0,1.0,0.0);
        glandular->DrawIntersectionPlane();
        for (size_t i=0;i<objects.size();i++) {
            objects[i]->ComputeIntersectionPlane(0.0, 1.0, 0.0, plane->translateY);
            objects[i]->DrawIntersectionPlane();
        }

        glMatrixMode(GL_PROJECTION);
        glPopMatrix();
        glViewport(0, 0, 100, 100);
        drawAxis();
        glViewport(0, 0, windowWidth, windowHeight);
    }
}

void GLWidget::resizeGL(int width, int height)
{
    glViewport(0, 0, width, height);
    windowWidth = width;
    windowHeight = height;
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();

    //glOrtho(-12 ,12, -12, 12,-100,100);
    gluPerspective(45,(double)width/(double)height,0.01,1000);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
}

void GLWidget::addGlandular(int num, vector<double> vec, vector<double> nor)
{
    glandular->CreateCellObject(num, vec, nor);
    glandular->setName(string("glandular"));
}

void GLWidget::drawGlandular()
{
    //drawTranslateAxis(0,0,0);
    //drawScaleAxis(glandular->getTranslateX()/R*2.0, glandular->getTranslateY()/R*2.0,
    //               glandular->getTranslateZ()/R*2.0);
    //glandular->DrawCellObject(0, selectObject, displayMode);
    if (selectMode==CELL_SELECT)
    {
        glandular->DrawCellObjectDirect(0, selectObject, secondSelectObject, displayMode);
        for (size_t i=0;i<objects.size();i++) {
            (objects[i])->DrawCellObjectDirect(i+2, selectObject, secondSelectObject, displayMode);
        }

        if(mode==CELL_TRANSLATE && selectObject > 1) {
            /*
            crossPlane = new CellObject();
            crossPlane->buildPlane(0.0, 0.0, 0, 0);
            crossPlane->setTranslate(objects[selectObject-2]->getTranslateX(), objects[selectObject-2]->getTranslateY(), objects[selectObject-2]->getTranslateZ());
            crossPlane->setScale(4.0);
            crossPlane->setRotateY(-Phi*180/pi);
            //crossPlane->setRotateZ(Theta*180/pi);
            //crossPlane->setRotateX(-Theta*180/pi);
            crossPlane->DrawCellObjectDirectTransparent(-2, CELL_TRIANGLE, HIGH_TRANSPARENCY, PURPLE);
            */
        }
        else {
            if(crossPlane != NULL) {
                delete crossPlane;
                crossPlane = NULL;
            }
        }

    } else if (selectMode==CELL_EDITMESHPOINT) {
        if (selectObject==0) {
            glandular->drawEditPoint();
            glandular->DrawCellObjectDirect(0, selectObject, secondSelectObject, displayMode);
            for (size_t i=0;i<objects.size();i++) {
                (objects[i])->DrawCellObjectDirect(i+2, selectObject, secondSelectObject, displayMode);
            }
        } else if (selectObject>1) {
            (objects[selectObject-2])->drawEditPoint();
            glandular->DrawCellObjectDirect(0, selectObject, secondSelectObject, displayMode);
            for (size_t i=0;i<objects.size();i++) {
                (objects[i])->DrawCellObjectDirect(i+2, selectObject, secondSelectObject, displayMode);
            }
        }
    } else if (selectMode==CELL_EDITMESHFACE) {
        if (selectObject==0) {
            glandular->drawEditFaces();
            for (size_t i=0;i<objects.size();i++) {
                (objects[i])->DrawCellObjectDirect(i+2, selectObject, secondSelectObject, displayMode);
            }
        } else if (selectObject>1) {
            glandular->DrawCellObjectDirect(0, selectObject, secondSelectObject, displayMode);
            (objects[selectObject-2])->drawEditFaces();
            for (size_t i=0;i<objects.size();i++) {
                if ((int)i!=selectObject-2)
                    (objects[i])->DrawCellObjectDirect(i+2, selectObject, secondSelectObject, displayMode);
            }
        }
    }
}

void GLWidget::reset()
{
    R = topR = frontR = rightR = 100;
    Theta = pi/6;
    Phi = pi/6;
    offsetX = topOffsetX = frontOffsetX = rightOffsetX = 0.0;
    offsetY = topOffsetY = frontOffsetY = rightOffsetY = 0.0;
}

void GLWidget::deleteSelectedObject()
{
    if (selectObject>1)
    {
        objects.erase(objects.begin()+selectObject-2);
    }
    selectObject = -1;
}

void GLWidget::generateMesh()
{
    if (selectObject > 1)
    {
        if (objects[selectObject - 2]->getType() == CELL_LINE)
        {
            objects[selectObject-2]->buildCylinder(objects[selectObject-2]->getCtrlPt2X(), objects[selectObject-2]->getCtrlPt2Y(), objects[selectObject-2]->getCtrlPt2Z(), 5, objects[selectObject-2]->getCtrlPt1X(), objects[selectObject-2]->getCtrlPt1Y(), objects[selectObject-2]->getCtrlPt1Z(), 5);
        }
    }
}

void GLWidget::deleteObject(int index)
{
    if ((size_t)index<objects.size())
    {
        objects.erase(objects.begin()+index);
    }
    if (selectObject == index+2)
    {
        selectObject = -1;
    }
}

void GLWidget::pasteObject()
{
    if (copyObject>1)
    {
        CellObject* obj = (objects[copyObject-2])->clone();
        objects.push_back(obj);
    }
}

void GLWidget::printObjects()
{
    for(long i=0.0; i < objects.size(); i++)
    {
        cout << objects[i]->getName() << endl;
    }
    cout << endl;
}

bool GLWidget::emptyScene()
{
    if(objects.empty())
    {
        return true;
    }
    else
    {
        return false;
    }
}
